/*
 * "Copyright (c) 2005 Stanford University. All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose, without fee, and without written
 * agreement is hereby granted, provided that the above copyright
 * notice, the following two paragraphs and the author appear in all
 * copies of this software.
 * 
 * IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF STANFORD UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 * 
 * STANFORD UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE
 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND STANFORD UNIVERSITY
 * HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 * ENHANCEMENTS, OR MODIFICATIONS."
 */


/**
 * The TOSSIM abstraction of a mote. By putting simulation state into
 * a component, we can scale and reference this state automatically
 * using nesC's rewriting, rather than managing and indexing into
 * arrays manually.
 *
 * @author Phil Levis
 * @date   August 19 2005
 */

// $Id: SimMoteP.nc,v 1.4 2006/12/12 18:23:32 vlahan Exp $



module SimMoteP {
  provides interface SimMote;
}

implementation {
  long long int euid;
  int appid;
  int timerfreq;

  float battery;
  float init_bat;
  float max_bat;

  sim_event_t senseInt;


  int sensedVal[5];

  sim_time_t startTime;
  bool isOn;
  sim_event_t* bootEvent;
  sim_time_t moteDied;
  sim_time_t prevTime;

  int num_sent_msg;
  int num_recv_msg;

  int ledstate[3];
  int cpustate;
  int radiostate;
  float total[3];
  

  async command void SimMote.setNewSensedValue(int type, int val) {
    sensedVal[type-1] = val;
  }

  async command int  SimMote.getSensedValue(int type) {
    return sensedVal[type-1];
  }


  async command int SimMote.getAppId() {
    return appid;
  }

  async command int SimMote.getTimerFreq() {
    return timerfreq;
  }


  async command void SimMote.setApplication(int app, int freq) {
    appid = app;
    timerfreq = freq;

    dbg("SimMoteP", "in setApplication, set app %i with freq %i.\n", appid, timerfreq);
    sim_main_start_mote(appid, timerfreq);  // motified by Mina Jung
  }


  async command void SimMote.setInterrupt(int type) {
    sim_main_interrupt_mote(type);
  }


  async command long long int SimMote.getEuid() {
    return euid;
  }
  async command void SimMote.setEuid(long long int e) {
    euid = e;
  }
  async command sim_time_t SimMote.getStartTime() {
    return startTime;
  }
  async command bool SimMote.isOn() {
    return isOn;
  }

  async command int SimMote.getVariableInfo(char* name, void** addr, size_t* size) {
    return __nesc_nido_resolve(sim_node(), name, (uintptr_t*)addr, (size_t*)size);
  }

  command void SimMote.turnOn() {
    float b1,b2,b3;
    b1 = battery; b2 = init_bat; b3 = max_bat;
    if (!isOn) {
      if (bootEvent != NULL) {
	bootEvent->cancelled = TRUE;
      }
      __nesc_nido_initialise(sim_node());
      startTime = sim_time();

      num_sent_msg = 0;
      num_recv_msg = 0;
      battery = b1;
      init_bat = b2;
      max_bat = b3;

      prevTime = startTime;

      moteDied.sec = -1;
      cpustate = 0;
      radiostate = 0;
      ledstate[0] = ledstate[1] = ledstate[2] = 0;
      total[0] = total[1] = total[2] = 0.0;

      dbg("SimMoteP", "in turnon, Setting start time to %i,%llu\n", startTime.sec, startTime.ticks);
      isOn = TRUE;

//      dbg("SimMoteP", "start with %i\n", appid);
//      sim_main_start_mote(appid);  // motified by Mina Jung
    }
  }

  async command void SimMote.turnOff() {
    isOn = FALSE;
  }

  async command void SimMote.CpuStateHandler(int newstate) {
    cpustate = newstate;
  }

  async command int SimMote.getCpuState() {
    return cpustate;
  }

  async command void SimMote.LedStateHandler(int bit, int newstate) {
    ledstate[bit] = newstate;
  }

  async command int SimMote.getLedState(int bit) {
    return ledstate[bit];
  }

  async command void SimMote.RadioStateHandler(int newstate) {
    radiostate = newstate;
  }

  async command int SimMote.getRadioState() {
    return radiostate;
  }

  async command void SimMote.AdcHandler(int newstate) {

  }

  async command void SimMote.CpuCycleHandler(int newstate) {

  }

  async command void SimMote.SensorStateHandler(int newstate) {
  
  }

  async command void SimMote.EepromStateHandler(int newstate) {

  }

  async command void SimMote.setMoteDied(sim_time_t newvalue) {
	moteDied = newvalue;
  }

  async command sim_time_t SimMote.getMoteDied() {
    return moteDied;
  }

  async command void SimMote.setPrevTime(sim_time_t newvalue) {
	prevTime = newvalue;
  }

  async command sim_time_t SimMote.getPrevTime() {
    return prevTime;
  }

  async command void SimMote.setBattery(float newvalue) {
    battery = newvalue;
  }

  async command void SimMote.setInitBattery(float value) {
    init_bat = value;
  }

  async command void SimMote.setMaxBattery(float value) {
    max_bat = value;
  }

  async command float SimMote.getBattery() {
    return battery;
  }

  async command float SimMote.getInitBattery() {
    return init_bat;
  }

  async command float SimMote.getMaxBattery() {
    return max_bat;
  }


  async command void SimMote.addTotalCurrent(int what, float newvalue) {
    total[what] += newvalue;
  }

  async command float SimMote.getTotalCurrent(int what) {
    return total[what];
  }

  async command void SimMote.increaseReceivedMsg() {
    num_recv_msg++;
  }
  
  async command int  SimMote.getReceivedMsg() {
    return num_recv_msg;
  }

  async command void SimMote.increaseSentMsg() {
    num_sent_msg++;
  }
  
  async command int  SimMote.getSentMsg() {
    return num_sent_msg;
  }



  long long int sim_mote_euid(int mote) __attribute__ ((C, spontaneous)) {
    long long int result;
    int tmp = sim_node();

    sim_set_node(mote);

    result = call SimMote.getEuid();

    sim_set_node(tmp);

    return result;
  }

  void sim_mote_set_euid(int mote, long long int id)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();

    sim_set_node(mote);

    call SimMote.setEuid(id);

    sim_set_node(tmp);
  }
  
  sim_time_t sim_mote_start_time(int mote) __attribute__ ((C, spontaneous)) {
    sim_time_t result;
    int tmp = sim_node();

    sim_set_node(mote);

    result = call SimMote.getStartTime();

    sim_set_node(tmp);

    return result;
  }

  int sim_mote_get_variable_info(int mote, char* name, void** ptr, size_t* len) __attribute__ ((C, spontaneous)) {
    int result;
    int tmpID = sim_node();

    sim_set_node(mote);

    result = call SimMote.getVariableInfo(name, ptr, len);
    dbg("SimMoteP", "Fetched %s of %i to be %p with len %i (result %i)\n", name, mote, *ptr, *len, result);

    sim_set_node(tmpID);

    return result;
  }
  
  void sim_mote_set_start_time(int mote, sim_time_t t) __attribute__ ((C, spontaneous)) {
    int tmpID = sim_node();

    sim_set_node(mote);

    startTime = t;
    dbg("SimMoteP", "in sim_mote_set_start_time, Setting start time to %i,%llu\n", startTime.sec, startTime.ticks);

    sim_set_node(tmpID);
    return;
  }
  
  bool sim_mote_is_on(int mote) __attribute__ ((C, spontaneous)) {
    bool result;
    int tmp = sim_node();

    sim_set_node(mote);

    result = call SimMote.isOn();

    sim_set_node(tmp);

    return result;
  }
  
  void sim_mote_turn_on(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();

    sim_set_node(mote);

    call SimMote.turnOn();

    sim_set_node(tmp);
  }
  
  void sim_mote_turn_off(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();

    sim_set_node(mote);

    call SimMote.turnOff();

    sim_set_node(tmp);
  }

  void sim_mote_boot_handle(sim_event_t* e) {
    char buf[128];

    sim_print_now(buf, 128);

    bootEvent = (sim_event_t*)NULL;
    dbg("SimMoteP", "in sim_mote_boot_handle, Turning on mote %i at time %s.\n", (int)sim_node(), buf);

    call SimMote.turnOn();

    dbg("SimMoteP", "in sim_mote_boot_handle, mote %i set app %i.\n", (int)sim_node(), e->app);
    call SimMote.setApplication((int)e->app, (int)e->timerfreq);

  }
  
  void sim_mote_enqueue_boot_event(int mote, int app, int freq) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_set_node(mote);

    if (bootEvent != NULL)  {
      if (bootEvent->time.sec == startTime.sec && bootEvent->time.ticks == startTime.ticks) {
	// In case we have a cancelled boot event.
	bootEvent->cancelled = FALSE;
	return;
      }
      else {
	bootEvent->cancelled = TRUE;
      }
    }
    
    bootEvent = (sim_event_t*) malloc(sizeof(sim_event_t));
    bootEvent->time = startTime;
    bootEvent->mote = mote;

    bootEvent->app = app; // Mina Jung
    bootEvent->timerfreq = freq;

    bootEvent->force = TRUE;
    bootEvent->data = NULL;
    bootEvent->handle = sim_mote_boot_handle;
    bootEvent->cleanup = sim_queue_cleanup_event;
    sim_queue_insert(bootEvent);

    dbg("SimMoteP", "enqueue boot event with %i,%i\n", app, mote);
    sim_set_node(tmp);
  }

  float time_diff(sim_time_t t_from, sim_time_t t_to)
  {
    return( (t_to.sec - t_from.sec) + (float)(t_to.ticks - t_from.ticks)/sim_ticks_per_sec());
  }

  float current_value(int type, int state) {
    if(type == 0) { /* cpu state */
      switch(state) { 
        case 0: /* idle */
		return 4.93;
		break;
        case 1: /* adc */
		return 0.32;
		break;
        case 2: /* extended standby */
		return 0.25;
		break;
        case 3: /* power save */
		return 0.009;
		break;
        case 4: /* standby */
		return 1.0;
		break;
        case 5: /* power down */
		return 0.0003;
		break;
        case 6: /* active */
		return 8.93;
		break;
      }
    }
    else if(type == 1) { /* radio state */
      switch(state) {
        case 0: /* off */
               return 0.0;
               break;
        case 1: /* rx mode*/
               return 19.7;
               break;
        case 2: /* tx default power */
               return 255.0;
               break;
        case 3: /* tx FB power */
               return  16.5;
               break;
        case 4: /* tx F7 power */ 
               return 15.2;
               break;
        case 5: /* tx F3 power */
               return 13.9;
               break;
        case 6: /* tx EF power */
               return 12.5;
               break;
        case 7: /* tx EB power */
               return 11.2;
               break;
        case 8: /* tx E7 power */
               return 9.9;
               break;
        case 9: /* tx E3 power */
               return 8.5;
               break;
        case 10: /* tx FF power */
               return 17.4;
               break;
      }
    }
    else if(type == 2) {
      switch(state) { /* led state */
        case 0: /* off */
               return 0.0;
               break;
        case 1: /* on */
               return 2.2;
               break;
      }
    }
 
    return 0.0;
  }


  double getRecoveryProbability( float remaining) {
    if(remaining >= 1)
      return 0.4;
    else if(remaining >= 0.9)
      return 0.367879441;
    else if(remaining >= 0.8)
      return 0.135335283;
    else if(remaining >= 0.7)
      return 0.049787068;
    else if(remaining >= 0.6)
      return 0.018315639;
    else if(remaining >= 0.5)
      return 0.006737947;
    else if(remaining >= 0.4)
      return 0.002478752;
    else if(remaining >= 0.3)
      return 0.000911882;
    else if(remaining >= 0.2)
      return 0.000335463;
    else if(remaining >= 0.1)
      return 0.00012341;
    else
      return 0.0000453999;
  }
  

  double getEfficiency( float demand) {
    if(demand >= 1378.061)
      return 0.316726684;
    else if(demand >= 1252.783)
      return 0.333751022;
    else if(demand >= 1138.894)
      return 0.35077536;
    else if(demand >= 1035.358)
      return 0.367799698;
    else if(demand >= 941.234)
      return 0.384824035;
    else if(demand >= 855.668)
      return 0.401382883;
    else if(demand >= 777.88)
      return 0.419803691;
    else if(demand >= 707.163)
      return 0.435431558;
    else if(demand >= 642.876)
      return 0.450546051;
    else if(demand >= 584.432)
      return 0.466412454;
    else if(demand >= 531.302)
      return 0.483627321;
    else if(demand >= 483.002)
      return 0.502360465;
    else if(demand >= 439.093)
      return 0.522522345;
    else if(demand >= 399.175)
      return 0.543878012;
    else if(demand >= 362.887)
      return 0.566123072;
    else if(demand >= 329.897)
      return 0.588932875;
    else if(demand >= 299.906)
      return 0.611993044;
    else if(demand >= 272.642)
      return 0.635017191;
    else if(demand >= 247.856)
      return 0.657755972;
    else if(demand >= 225.324)
      return 0.680000453;
    else if(demand >= 204.84)
      return 0.701581843;
    else if(demand >= 186.218)
      return 0.722369056;
    else if(demand >= 169.289)
      return 0.742265064;
    else if(demand >= 153.899)
      return 0.761202713;
    else if(demand >= 139.908)
      return 0.779140421;
    else if(demand >= 127.19)
      return 0.796058027;
    else if(demand >= 115.627)
      return 0.811952955;
    else if(demand >= 105.115)
      return 0.82683675;
    else if(demand >= 95.559)
      return 0.840732051;
    else if(demand >= 86.872)
      return 0.853669968;
    else if(demand >= 78.975)
      return 0.865687852;
    else if(demand >= 71.795)
      return 0.876827442;
    else if(demand >= 65.268)
      return 0.887133315;
    else if(demand >= 59.335)
      return 0.896651643;
    else if(demand >= 53.941)
      return 0.905429182;
    else if(demand >= 49.037)
      return 0.913512479;
    else if(demand >= 44.579)
      return 0.920947259;
    else if(demand >= 40.527)
      return 0.927777952;
    else if(demand >= 36.842)
      return 0.934047361;
    else if(demand >= 33.493)
      return 0.939796409;
    else if(demand >= 30.448)
      return 0.945063992;
    else if(demand >= 27.68)
      return 0.949886879;
    else if(demand >= 25.164)
      return 0.954299676;
    else if(demand >= 22.876)
      return 0.958334825;
    else if(demand >= 20.797)
      return 0.962022639;
    else if(demand >= 18.906)
      return 0.965391356;
    else if(demand >= 17.187)
      return 0.968467216;
    else if(demand >= 15.625)
      return 0.971274544;
    else if(demand >= 14.204)
      return 0.973835848;
    else if(demand >= 12.913)
      return 0.976171913;
    else if(demand >= 11.739)
      return 0.978301907;
    else if(demand >= 10.672)
      return 0.980243478;
    else if(demand >= 9.702)
      return 0.982012858;
    else if(demand >= 8.82)
      return 0.983624956;
    else if(demand >= 8.018)
      return 0.985093455;
    else if(demand >= 7.289)
      return 0.986430897;
    else if(demand >= 6.626)
      return 0.987648777;
    else if(demand >= 6.024)
      return 0.988757613;
    else if(demand >= 5.476)
      return 0.989767029;
    else if(demand >= 4.979)
      return 0.990685825;
    else if(demand >= 4.526)
      return 0.99152204;
    else if(demand >= 4.114)
      return 0.992283018;
    else if(demand >= 3.74)
      return 0.992975463;
    else if(demand >= 3.4)
      return 0.993605494;
    else if(demand >= 3.091)
      return 0.994178692;
    else if(demand >= 2.81)
      return 0.994700147;
    else if(demand >= 2.555)
      return 0.995174499;
    else if(demand >= 2.323)
      return 0.995605978;
    else if(demand >= 2.111)
      return 0.995998439;
    else if(demand >= 1.919)
      return 0.996355392;
    else if(demand >= 1.745)
      return 0.996680036;
    else if(demand >= 1.586)
      return 0.996975284;
    else if(demand >= 1.442)
      return 0.997243788;
    else if(demand >= 1.311)
      return 0.997487962;
    else if(demand >= 1.192)
      return 0.997710004;
    else if(demand >= 1.083)
      return 0.997911915;
    else if(demand >= 0.985)
      return 0.998095516;
    else if(demand >= 0.895)
      return 0.998262463;
    else if(demand >= 0.814)
      return 0.998414264;
    else if(demand >= 0.74)
      return 0.99855229;
    else if(demand >= 0.673)
      return 0.998677789;
    else if(demand >= 0.612)
      return 0.998791897;
    else if(demand >= 0.556)
      return 0.998895645;
    else if(demand >= 0.505)
      return 0.998989974;
    else if(demand >= 0.459)
      return 0.999075737;
    else if(demand >= 0.418)
      return 0.999153712;
    else if(demand >= 0.38)
      return 0.999224605;
    else if(demand >= 0.345)
      return 0.999289059;
    else if(demand >= 0.314)
      return 0.999347657;
    else if(demand >= 0.285)
      return 0.999400933;
    else if(demand >= 0.259)
      return 0.999449368;
    else if(demand >= 0.236)
      return 0.999493402;
    else if(demand >= 0.214)
      return 0.999533436;
    else if(demand >= 0.195)
      return 0.999569832;
    else if(demand >= 0.177)
      return 0.999602921;
    else if(demand >= 0.161)
      return 0.999633003;
    else if(demand >= 0.146)
      return 0.999660351;
    else if(demand >= 0.133)
      return 0.999685214;
    else if(demand >= 0.121)
      return 0.999707817;
    else if(demand >= 0.11)
      return 0.999728366;
    else if(demand >= 0.1)
      return 0.999747047;
    else
      return 1.0;
  }

  void update_totals(int mote, sim_time_t t)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    float td;
    float bat_val;
    float maxbat;
    float initB;
    float vol = 3.0;
    sim_time_t died, prev_time;
    float prev_bat;
    float current_drawn = 0.0;
    float current_cutoff = 0.1;
    float cur_val;
    int i, j, states, num_on = 0;
    bat_val = get_current_battery(mote);
    maxbat = get_max_battery(mote);
    initB = get_init_battery(mote);

    sim_set_node(mote);

    bat_val = call SimMote.getBattery();
    maxbat = call SimMote.getMaxBattery();
    initB = call SimMote.getInitBattery();


    died = call SimMote.getMoteDied();
    prev_time = call SimMote.getPrevTime();
    td = time_diff(prev_time, t);

    if( bat_val < 0 && died.sec == -1){
      call SimMote.setMoteDied(t);
    }
    prev_bat = bat_val;

    for( i = 0; i < 3; i++) {
      switch (i) {
        case 0:
               states = call SimMote.getCpuState();
               current_drawn += current_value(i, states);
               break;
        case 1:
               states = call SimMote.getRadioState();
               current_drawn += current_value(i, states);
               break;
        case 2:
               for(j = 0; j < 3; j++){
                 states = call SimMote.getLedState(j);
                 if(states)
                   num_on++;
               }
               current_drawn += current_value(i, 1)*num_on;
               break;
      }
      cur_val = current_value(i, states) * td * vol;
      call SimMote.addTotalCurrent(i, cur_val);
    }
    if(current_drawn > current_cutoff){
      bat_val -= td /3600 * current_drawn /getEfficiency(current_drawn);
    }
    else {
      float td_remaining = td;
      if(getRecoveryProbability(bat_val/maxbat) > 0) {
        td_remaining = td;
        while(td_remaining > 0) {
          if(sim_random()/1000000000000000000000.0 < getRecoveryProbability(bat_val/maxbat)) {
            bat_val += 0.000001;
          }
          if( bat_val > maxbat ) {
            bat_val = max_bat;
          }
          td_remaining -= 0.0005;
        } 
      }
    }
    
    call SimMote.setBattery(bat_val);

    sim_set_node(tmp);
  }

  void handle_cpu_event(int mote, sim_time_t t, int newstate)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_set_node(mote);

    call SimMote.CpuStateHandler(newstate);
    call SimMote.setPrevTime(t);

    sim_set_node(tmp);
  }

  void handle_led_event(int mote, sim_time_t t, int bit, int newstate)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_set_node(mote);

    call SimMote.LedStateHandler(bit, newstate);
    call SimMote.setPrevTime(t);

    sim_set_node(tmp);
  }

  void handle_radio_event(int mote, sim_time_t t, int newstate)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_set_node(mote);

    call SimMote.RadioStateHandler(newstate);
    call SimMote.setPrevTime(t);

    sim_set_node(tmp);
  }

  void handle_adc_event(int mote, sim_time_t t, int newstate)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_set_node(mote);

    call SimMote.AdcHandler(newstate);
    call SimMote.setPrevTime(t);

    sim_set_node(tmp);
  }

  void handle_sensor_event(int mote, sim_time_t t, int newstate)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_set_node(mote);

    call SimMote.SensorStateHandler(newstate);
    call SimMote.setPrevTime(t);

    sim_set_node(tmp);
  }

  void handle_eeprom_event(int mote, sim_time_t t, int newstate)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_set_node(mote);

    call SimMote.EepromStateHandler(newstate);
    call SimMote.setPrevTime(t);

    sim_set_node(tmp);
  }

  void handle_cpu_cycle_event(int mote, sim_time_t t, int newstate)  __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_set_node(mote);

    call SimMote.CpuCycleHandler(newstate);
    call SimMote.setPrevTime(t);

    sim_set_node(tmp);
  }

  float second_update_totals(int mote, int sec) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    float bat_val;
    sim_time_t t;
    t.sec = sec;
    t.ticks = 0;

    update_totals(mote, t);

    sim_set_node(mote);
    call SimMote.setPrevTime(t);
    bat_val = call SimMote.getBattery();
    sim_set_node(tmp);

    return bat_val;
  }

  float get_current_battery(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    float bat_val;

    sim_set_node(mote);
    bat_val = call SimMote.getBattery();
    sim_set_node(tmp);

    return bat_val;
  }


  float get_init_battery(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    float bat_val;

    sim_set_node(mote);
    bat_val = call SimMote.getInitBattery();
    sim_set_node(tmp);

    return bat_val;
  }


  float get_max_battery(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    float bat_val;

    sim_set_node(mote);
    bat_val = call SimMote.getMaxBattery();
    sim_set_node(tmp);

    return bat_val;
  }


  float get_total_current(int mote, int type) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    float cur_val;

    sim_set_node(mote);

    cur_val = call SimMote.getTotalCurrent(type);

    sim_set_node(tmp);

    return cur_val;
  }

  void increase_num_sent_msg(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();

    sim_set_node(mote);

    call SimMote.increaseSentMsg();

    sim_set_node(tmp);
  }

  void increase_num_recv_msg(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();

    sim_set_node(mote);

    call SimMote.increaseReceivedMsg();

    sim_set_node(tmp);
  }
 

  int get_num_sent_msg(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    int val;

    sim_set_node(mote);

    val = call SimMote.getSentMsg();

    sim_set_node(tmp);

    return val;
  }
   
  int get_num_recv_msg(int mote) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    int val;

    sim_set_node(mote);

    val = call SimMote.getReceivedMsg();

    sim_set_node(tmp);

    return val;
  }

  void set_sensed_value(int mote, int type, int val) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();

    sim_set_node(mote);

    call SimMote.setNewSensedValue(type, val);

    sim_set_node(tmp);
  }

  void set_bat_info(int mote, float init, float max) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();

    sim_set_node(mote);

    call SimMote.setBattery(init);

    call SimMote.setInitBattery(init);

    call SimMote.setMaxBattery(max);

    sim_set_node(tmp);
  }


  void change_current_battery(int mote, float value) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();

    sim_set_node(mote);

    call SimMote.setBattery(value);

    sim_set_node(tmp);
  }



  int get_sensed_value(int mote, int type) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    int val;

    sim_set_node(mote);

    val = call SimMote.getSensedValue(type);

    sim_set_node(tmp);
   
    return val;
  }


  void sensor_interrupt_handle(sim_event_t* e) {


    int tmp = sim_node();

    sim_set_node(e->mote);

    call SimMote.setInterrupt(e->app);


    sim_set_node(tmp);

  }

  void set_interrupted_value(int mote, int type, int sec) __attribute__ ((C, spontaneous)) {
    int tmp = sim_node();
    sim_time_t ocr_time;
    ocr_time.sec = sec;
    ocr_time.ticks = sim_random()%sim_ticks_per_sec();

    sim_set_node(mote);

    senseInt.mote = mote;
    senseInt.time = ocr_time;
    senseInt.app = type;
    senseInt.force = 1;
    senseInt.cancelled = 0;
    senseInt.handle = sensor_interrupt_handle;
    senseInt.cleanup = sim_queue_cleanup_none;

    sim_queue_insert(&senseInt);

    sim_set_node(tmp);

  }

}
